iT邦幫忙

2024 iThome 鐵人賽

DAY 28
0
自我挑戰組

ABAP 基礎30天學習筆記系列 第 28

Day28_為RESTful API添加程式邏輯(上)_Validation

  • 分享至 

  • xImage
  •  

原文連結:Adding ABAP logic

Validation

檢查主鍵

在ABAP RESTful API中,資料表的鍵通常由client欄位與UUID欄位組成,其值在建立新的實體時會由系統自動指派。這類型的欄位可以確保資料被唯一識別。

然而,除了前述的technical key,在物件中還有另一個語意化的鍵,以前一章的例子而言是航空公司與航班的組合鍵,其組合也必須具有唯一性。

https://ithelp.ithome.com.tw/upload/images/20240919/20113802fm5MfvuFyu.png

為了確保資料的唯一性,我們需要設置檢查主鍵的Validation。可以在CDS視圖的行為定義(behavior definition)中宣告Validation,並於行為實例(behavior implementation)的class中實例化。

檢查輸入

雖然應用可以對資料進行增刪改查,但目前還未包含一致性的檢查,可能導致創建不存在的航空公司、或者出發和抵達機場一樣的錯誤情境。

因此,在設計時也需要考量諸多的Validation條件。

建立錯誤訊息

在我們建立Validation之前,需要先建立想提示的文字,這時可以使用message class。message class是一個可以存入1000則提示訊息的類別,且每則訊息都有一個獨立編號,如圖所示:
https://ithelp.ithome.com.tw/upload/images/20240919/201138024ezZllkTb6.png

File → New → Other中可以搜尋message,選擇message class
https://ithelp.ithome.com.tw/upload/images/20240919/20113802vYOgOYDX2O.png
2.
輸入編號及想顯示的訊息
https://ithelp.ithome.com.tw/upload/images/20240919/201138023llhhyujPq.png

訊息中還可以使用佔位符&<數字>,在顯示時會轉換成對應的值。每則訊息中最多能使用四個佔位符。

Validation的語法

在BO的行為定義中,我們可以定義前述的那些Validation。Validation應在資料被保存時就進行驗證,例如新增或修改時。

"在行為定義中"
validation CheckSemanticKey
    on save { create; update; }

當在行為定義中寫Validation的時候,系統會提示該方法不存在,此時可以對Validation按下ctrl+1並雙擊,在行為實體中添加方法。

"在行為實體中"
CLASS 1cl_handler DEFINITION INHERITING FROM cl_abap_behavior_handler.

PRIVATE SECTION.

METHODS CheckSemanticKey 
FOR VALIDATE ON SAVE 
IMPORTING keys FOR
Connection~CheckSemantickey.

ENDCLASS.

行為實體將會是behavior pool中的local class。該方法中的FOR VALIDATE ON SAVE語句可視為Validation的實例化。

這裡有一個導入參數'keys',這是一個存放了被新增或修改的鍵的internal table,可以用來讀取使用者輸入的實際資料。

FOR Connection~CheckSemanticKey則用來把這個方法與行為定義的CheckSemanticKeyValidation進行連結,Connection是CDS視圖的別名。

Validation流程

https://ithelp.ithome.com.tw/upload/images/20240919/20113802xrW1JKXzxZ.png

當Validation被觸發,相應的實例也會被呼叫,可以透過參數'keys'結合EML讀取所需的資料欄位。

當我們讀取到資料,此時可以執行開發者設定好的Validation。一旦驗證失敗,會在此時顯示錯誤訊息,並通知系統不要寫入這個變更到資料庫。

接著會用存取航班的三個Validation範例,逐一介紹上圖中驗證流程的寫法,主要在Validation 1中會有流程詳述,其餘會簡單概述。

Validation 1:檢查主鍵的唯一性

讀入資料

"定義讀入表格"
DATA read_keys   TYPE TABLE FOR READ IMPORT zs4d400_r_connection.
"定義輸出結果表格"
DATA connections TYPE TABLE FOR READ RESULT zs4d400_r_connection. 

"自動對應keys參數"
read_keys = CORRESPONDING #( keys ).

"指定要讀取的行為定義"
READ ENTITIES OF zs4d400_r_connection IN LOCAL MODE
ENTITY Connection"讀取的實體"
FIELDS (UUID CarrierID ConnectionID )"欄位列表"
  WITH read_keys"鍵列表"
RESULT connections."存放結果到result internal table"

這裡使用到了前面章節有提及的EML,新增的資料會透過參數'keys'傳給Validation。

在需要被驗證的資料裡,其語意化鍵欄位有代表航線的CarrierID以及代表航班號碼的ConnectionID,另外也需要UUID欄位。

當成功讀入使用者輸入的資料,可以使用可以使用 CarrierIDConnectionID的值來檢查是否已被處理。由於組合鍵可能會在草稿或已啟用的表格中,可以使用union來同時查看這兩個表:

LOOP AT connections INTO DATA(connection).

SELECT FROM zs4d400aconn
FIELDS uuid
 WHERE carrier_id    = @connection-Carrier ID
   AND connection_id = @connection-ConnectionID
   AND uuid          <> @connection-uuid

UNION

SELECT FROM zsd400dconn
FIELDS uuid
 WHERE carrierid    = @connection-CarrierID
   AND connectionid = @connection-Connection ID
   AND uuid         <> @connection-uuid

INTO TABLE @DATA(check_result).

ENDLOOP.

這個查詢結果應為,如果不為空,代表存在相同的CarrierIDConnectionID的組合,也就是使用者目前建立的資料(鍵)是重複的,必須拒絕。

建立錯誤訊息

當前述的鍵重複組合已經存在,搜尋將會被存入表格check_result當中,這時我們可以透過確認該表格是否有內容,回傳錯誤提示。

"檢查表格是否有回傳結果"
IF check_result IS NOT INITIAL.

DATA(message) = me->new_message(
id = 'ZS4D400' "message class名稱"
       number = '001' "編號"
     severity = ms-error "嚴重性"
           v1 = connection-CarrierID "佔位符v1"
           v2 = connection-ConnectionID )."佔位符v2"

ENDIF.

首先需要先在message class中建立錯誤訊息,可以使用me自我引用並呼叫方法new_message( ),參數ID、訊息編號(number)和嚴重性(severity)都是必填項。
參數ID是包含該錯誤訊息的message class名稱;嚴重性則可分為成功、訊息、警告與錯誤,行為實例宣告嚴重性前會接一個常數ms-,例如本例中的ms-error

另外,錯誤訊息還可包含最多四個導入參數v1~v4(可選),當顯示錯誤訊息就會出現對應值,上例的對應值是兩個組合鍵的內容。

呼叫上述方法的結果會是引用一個物件,下一步將傳遞該物件,讓錯誤訊息可以回傳給OData,並在應用程式中顯示。

顯示錯誤訊息

設置完錯誤訊息,此時使用reported structure來進行回傳,這是一個隱性的變更參數(changing parameter)及structure,擁有一個包含BO別名的欄位,這個欄位則是一個internal table。

為了回傳訊息,需要以下三步驟:

  1. 將受Validation影響的鍵添加到internal table中,這裡可以使用@tky對欄位分組,直接選取欄位組的名稱而無須指定每一欄。

  2. 將錯誤訊息的物件加到表格中,這裡可以把該物件指派給internal table中的%msg欄位

  3. 綁定錯誤訊息與受影響欄位,以確保在應用程式中被強調,並且這也能作為導覽使用者的資訊,使用internal table中的%element欄位綁定@tky@msg

"建立回報用structure"
DATA reported_record LIKE LINE OF reported-connection.
reported_record-%tky = line-%tky. "存入受影響的鍵"
reported_record-%msg = msg. "存入錯誤訊息"
reported_record-%element-CarrierID = if_abap_behv=>mk-on. ""

"3. 存入回報用internal table"
APPEND reported_record TO reported-connection.

如上例,reported_recordstructure的資料型別來自internal tablereported-connection,可以使用structure中的%tky填入被變更的鍵(1),這欄將作為workarea,並從保存了使用者輸入值的internal table中提取資料。

接著,將剛剛用new_message( )建立的錯誤訊息存入欄位%msg(2)。

最後,為了將錯誤訊息與欄位CarrierID相互綁定(3),使用structure%element,其包含了視圖中的所有欄位。

如果將欄位設置為true,相關聯的輸入欄位會在在應用程式中高亮顯示。可以使用structure中的結構常數if_abap_behv=>mk-onif_abap_behv=>mk-off來達成,用onoff來代表檢查/true不檢查/false

注意,這裡不能使用全域常數abap_trueabap_false,因為它們的型別是不相容的。

拒絕存取不正確的資料

除了傳遞錯誤訊息,也要向系統通知拒絕存入不正確的資料。這裡使用failedstructure來進行Validation,failed是一個存在於所有Validation方法中的隱式變更參數,當驗證失敗時就可回報該參數以避免資料存入。

若要將報告回報為failed,要將該欄位群組%tky加到failed-Connection這個internal table的%tky欄位群組中。

Validation 2:檢查輸入資料是否存在

下一個Validation要檢查的是使用者輸入的航空公司是否真實存在,如下例,首先先用EMLREAD ENTITIES讀入使用者的輸入資料,在這個例子僅需讀取欄位CarrierID

READ ENTITIES OF zs4d400_r_connection IN LOCAL MODE
ENTITY Connection
FIELDS (CarrierId )
  WITH CORRESPONDING #( keys)
RESULT DATA(connections).

接著,用SELECT SINGLE語句讀取CDS視圖/dmo/i_carrier,並檢查給定的航班是否存在。

如果存在,全域常數abap_true('X')會被置於目標航班的欄位中以供偵測欄位存在。如果搜尋結果RESULT仍維持初始值,代表沒搜到相關欄位,需要用下面的if條件式呼叫錯誤題示並記錄在failedstructure中,如同上一個範例。

LOOP AT Connections INTO DATA(line).

SELECT SINGLE FROM /dmo/i_carrier FIELDS @abap_true WHERE AirlineID = @line-CarrierID INTO @DATA(exists). 

"如果abap_true為初始值"
IF exists <> abap_true

"此區放置錯誤訊息傳遞及回報"
...

ENDIF.

ENDLOOP.

Validation 3:檢查互斥欄位是否重複

由於出發機場與抵達機場不可相同,最後一個檢查會來檢查這兩個欄位的輸入值是否重複。第一步一樣先用READ ENTITIES讀入使用者輸入的資料,這次要讀AirportFromIDAirportToID欄位的值。

READ ENTITIES OF zs4d400_r_connection IN LOCAL MODE
ENTITY Connection
FIELDS (AirportFromID AirportToID )
  WITH CORRESPONDING #( keys )
RESULT DATA (connections).
LOOP AT connections INTO DATA(connection).

"如果出發地與抵達地相同"
IF connection-airportfromID = connection-airporttoID.

"建立錯誤訊息"
DATA(message) = me->new_message(
                    id = 'ZS4D400'
                    number = '003'
                    severity = ms-error ).
    
"此區放置錯誤訊息傳遞及回報"
    ...
                    
ENDIF.

ENDLOOP.

當出發及抵達的機場相同,則顯示相應錯誤訊息(上例)並填入保存錯誤的structures(如前例)。

明天來添加Determination的程式邏輯!


上一篇
Day27_ABAP RESTful API架構(下)_物件生成器
下一篇
Day29_為RESTful API添加程式邏輯(下)_Determination
系列文
ABAP 基礎30天學習筆記30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言